#include "mvc/model/aircrafts/aircraft.h"
#include "mvc/model/aircrafts/aircraft_rcurves.h"
#include "mvc/model/aircrafts/aircraft_parameters.h"
#include "mvc/model/geometry.h"
#include "mvc/model/station.h"
#include "common/log/QsLog.h"
#include "assert.h"

#include "common/geometry_calcs.h"
#include "common/texture_indexs.h"
#include "common/colours.h"

#include <GL/glu.h>
#include <GL/glut.h>

/**
  * The Aircraft constructor
  * id -  the id of the configuration
  * parameters - the parameters needed to create the geometry
  * airfoils - the airfoils needed to create the reference curves
  */
Aircraft::Aircraft(int id, Parameters *parameters, Airfoils_curve_map *airfoils)
    : Configuration(id, parameters)
{
    _airfoils = airfoils;
    is_refcur_map_generated = false;
    is_refcurves_generated = false;
    is_configuration_generated = false;
}

Aircraft::~Aircraft()
{
    if(!_airfoils)
        delete _airfoils;
}

/**
  * Returns a geometry that belongs to the configuration
  * g_index - the geometry index in the geometries vector
  * returns a geometry belongs to the configuration
  */
const AGeometry &Aircraft::get_a_geometry(_genum g_index) const
{
    return *(_geometries.at(g_index));
}

/**
  * Return the panels of the wings-fuselage intersection.
  */
QVector<int> Aircraft::get_wings_fuselage_intersection_panels() const
{
    QVector<int> panels;

    int npc = (*_parameters)[s_wings][wings_npc];

    panels.resize(npc * 2);
    for(int i = 0; i < npc; i++)
    {
        panels[i] = wf_start_intersection_panel + (i * npc);
        panels[i + npc] = panels.at(i) + 1;
    }

    return panels;
}

//
// Protected Methods
//

/**
  * Generate the geometry reference curves index
  */
void Aircraft::generate_reference_curves_index()
{
//    QLOG_INFO() << "Aircraft::generate_reference_curves_index";
    int index = 0;

    index = generate_rc_fuselage_index(index);
    index = generate_rc_wings_index(index);
    index = generate_rc_htail_index(index);
    index = generate_rc_vtail_index(index);

    reference_curves.resize(index);

    QLOG_INFO() << "Aircraft<Reference curves generated with index:> " << index << endl;

    is_refcur_map_generated = true;
}

/**
  * Generate the fuselage reference curves index
  * c_index - the current index of a free space on the vector of geometries.
  * the next index of a free space on the vector of geometries.
  * return the last free index
  */
int Aircraft::generate_rc_fuselage_index(int c_index)
{
//    QLOG_INFO() << "Aircraft::generate_rc_fuselage_index ";
    reference_curves_map.insert(irc_snout_fuselage, c_index++);
    reference_curves_map.insert(frc_snout_fuselage, c_index++);
    reference_curves_map.insert(irc_front_fuselage, reference_curves_map[frc_snout_fuselage]);

    int knpc = ((*_parameters)[s_wings])[wings_npc] + 1;
    for(int i = 0; i < knpc; i++)
    {
        QString c_curve = QString(rc_wing_fuselage).append(QString::number(i));
        reference_curves_map.insert(c_curve, c_index++);
    }

    QString initial_wing_fuselage_rc =  QString(rc_wing_fuselage).append(QString::number(0));
    QString final_wing_fuselage_rc =  QString(rc_wing_fuselage).append(QString::number(knpc - 1));;
    reference_curves_map.insert(frc_front_fuselage, reference_curves_map[initial_wing_fuselage_rc]);
    reference_curves_map.insert(irc_wing_fuselage, reference_curves_map[initial_wing_fuselage_rc]);
    reference_curves_map.insert(frc_wing_fuselage, reference_curves_map[final_wing_fuselage_rc]);

    reference_curves_map.insert(irc_back_fuselage, reference_curves_map[final_wing_fuselage_rc]);
    reference_curves_map.insert(frc_back_fuselage, c_index++);

    reference_curves_map.insert(irc_tail_fuselage, reference_curves_map[frc_back_fuselage]);
    reference_curves_map.insert(frc_tail_fuselage, c_index++);

    return c_index;
}

/**
  * Generate the wing reference curves index
  * c_index - the current index of a free space on the vector of geometries.
  * the next index of a free space on the vector of geometries.
  * return the last free index.
  */
int Aircraft::generate_rc_wings_index(int c_index)
{
//    QLOG_INFO() << "Aircraft::generate_rc_wings_index";
    reference_curves_map.insert(irc_wings, c_index++);
    reference_curves_map.insert(frc_wings, c_index++);

    return c_index;
}

/**
  * Generate the horizontal tail reference curves index
  * c_index - the current index of a free space on the vector of geometries.
  * the next index of a free space on the vector of geometries.
  * return the last free index.
  */
int Aircraft::generate_rc_htail_index(int c_index)
{
//    QLOG_INFO() << "Aircraft::generate_rc_htail_index";
    reference_curves_map.insert(irc_horizontal_tail, c_index++);
    reference_curves_map.insert(frc_horizontal_tail, c_index++);

    return c_index;
}

/**
  * Generate the vertical tail reference curves index
  * c_index - the current index of a free space on the vector of geometries.
  * the next index of a free space on the vector of geometries.
  * return the last free index.
  */
int Aircraft::generate_rc_vtail_index(int c_index)
{
//    QLOG_INFO() << "Aircraft::generate_rc_vtail_index";
    reference_curves_map.insert(irc_vertical_tail, reference_curves_map[irc_horizontal_tail]);
    reference_curves_map.insert(frc_vertical_tail, c_index++);

    return c_index;
}

/**
  * Generate all the reference curves of the geometry
  */
void Aircraft::generate_reference_curves()
{
//    QLOG_INFO() << "Aircraft::generate_reference_curves";
    int knpcf = ((*_parameters)[s_wings])[wings_npc] + 1;
    int knpcvt = (*_parameters)[s_horizontal_tail][htail_npc] + 1;

    generate_wings_refcurves();
    generate_fuselage_refcurves(knpcf);
    generate_horizontal_tail_refcurves();
    generate_vertical_tail_refcurves(knpcvt);

    is_refcurves_generated = true;
}

/**
  * Generate the fuselage reference curves
  */
void Aircraft::generate_fuselage_refcurves(int knpc)
{
//    QLOG_INFO() << "Aircraft::generate_fuselage_refcurves";
    float ln = ((*_parameters)[s_fuselage])[fuselage_ln];
    float l = ((*_parameters)[s_fuselage])[fuselage_l];
    float lt = ((*_parameters)[s_fuselage])[fuselage_lt];
    float dn = ((*_parameters)[s_fuselage])[fuselage_dn];
    float d = ((*_parameters)[s_fuselage])[fuselage_d];
    float dt = ((*_parameters)[s_fuselage])[fuselage_dt];
    float xnfs = ((*_parameters)[s_fuselage])[fuselage_xnfs];

    // snout fuselage reference curves
    create_fcurve(reference_curves_map[irc_snout_fuselage], dn / 2.0, xnfs, Point(1.0, 0.0));
    create_fcurve(reference_curves_map[frc_snout_fuselage], d / 2.0, xnfs - ln, Point(1.0, 0.0));

    // center fuselage reference curves
    int rcifw_index = reference_curves_map[irc_wings];

    for(int i = 0; i < knpc; i++)
    {
        QString rcurve(rc_wing_fuselage);
        rcurve.append(QString::number(i));
        int c_index = reference_curves_map[rcurve];

        Point3D *cpoint = reference_curves[rcifw_index].at(i);

        create_fcurve(c_index, d / 2.0, cpoint->x, Point(cpoint->y, -cpoint->z), false);
    }

    // tail fuselage reference curves
    create_fcurve(reference_curves_map[irc_tail_fuselage], d / 2.0, -(l - xnfs - lt), Point(1.0, 0.0));
    create_fcurve(reference_curves_map[frc_tail_fuselage], dt / 2.0, -(l - xnfs), Point(1.0, 0.0));
}

/**
  * Create a reference curve that belongs to fuselage
  */
void Aircraft::create_fcurve(int c_index, double radio, double lenght,
                             Point fstp, bool to_scale)
{
//    QLOG_INFO() << "Aircraft::create_fcurve";
    QVector<Point *> ucurve;

    double knpf = (*_parameters)[s_fuselage][fuselage_npf] + 1;

    if(to_scale)
        create_semicircle(knpf, fstp, 1.0, ucurve);
    else
        create_semicircle(knpf, fstp, radio, ucurve);

    Refcurve &ref_curve = reference_curves[c_index];
    ref_curve.resize(knpf);

    for(int i = 0; i < ucurve.size(); i++)
    {
        Point *cpoint = ucurve.at(i);

        Point3D *cp = new Point3D(0.0, cpoint->x, -cpoint->y);

        if(to_scale)
            cp->scale(radio);

        cp->translate(Point3D(lenght, 0.0, 0.0));

        ref_curve[i] = cp;

        delete cpoint;
    }
}

/**
  * Generate the reference curves of the wings
  */
void Aircraft::generate_wings_refcurves()
{
//    QLOG_INFO() << "Aircraft::generate_wings_refcurves";
    QMap<QString, float> &wings_params = (*_parameters)[s_wings];
    QMap<QString, float> &fuselage_params = (*_parameters)[s_fuselage];

    int knpc = wings_params[wings_npc] + 1;
    double diameter = fuselage_params[fuselage_d];

    create_wcurve(reference_curves_map[irc_wings], knpc, wings_root, 0.0,
                  wings_params[wings_crf], wings_params[wings_arf], 0.0, 0.0, NULL);
    create_wcurve(reference_curves_map[frc_wings], knpc, wings_join,
                  wings_params[wings_sib], wings_params[wings_cj], wings_params[wings_aj],
                  wings_params[wings_dib], wings_params[wings_lib], NULL);
    create_wcurve(reference_curves_map[frc_externw], knpc, wings_wingtip,
                  wings_params[wings_sib] + wings_params[wings_sob], wings_params[wings_ct],
                  wings_params[wings_at], wings_params[wings_dob], wings_params[wings_lob], NULL);

    calculate_wings_fuselage_intersection(reference_curves_map[irc_wings],
                                          reference_curves_map[frc_wings],
                                          knpc, diameter);
}

/**
  * Calculate the intersection between fuselage and wings
  */
void Aircraft::calculate_wings_fuselage_intersection(int irc_index, int frc_index,
                                                     int knpc, double diameter)
{
//    QLOG_INFO() << "Aircraft::calculate_wings_fuselage_intersection";
    Point3D *p0, *p1;
    Point3D *vector, *res;
    double ta;

    Refcurve &fwing_rcurve = reference_curves[irc_index];
    Refcurve &lwing_rcurve = reference_curves[frc_index];

    for(int i = 0; i < knpc; i++)
    {
        p0 = fwing_rcurve.at(i);
        p1 = lwing_rcurve.at(i);

        ta = get_ta(*p0, *p1, diameter / 2.0);

        vector = *p0 - *p1;
        res = find_a_point(*p0, *vector, ta);

        p0->x = res->x;
        p0->y = res->y;
        p0->z = res->z;

        delete res;
        delete vector;
    }
}

/**
* Generate the a wing reference curve specified with 'rcurve'.
*/
void Aircraft::create_wcurve(int index_curve, int nknots, const QString &rcurve, double wingspan,
                             double scale_value, double rotate_value, double arrow_angle,
                             double dihedral_angle, Point3D *locate_point)
{
//  QLOG_INFO() << "Aircraft::create_wcurve with index: " << index_curve;
  QVector<Point *> airfoil_curve;

  Refcurve &ref_curve = reference_curves[index_curve];

  airfoil_curve = (*_airfoils)[rcurve];

  Point3D *p;

  double incr = 1.0 / nknots;
  double next = 0.0;
  for(int index = 0; index < nknots; index++)
  {
      if(index == 0)
          p = new Point3D(airfoil_curve.last()->x, 0.0, airfoil_curve.last()->y);
      else if(index == nknots - 1)
          p = new Point3D(airfoil_curve.first()->x, 0.0, airfoil_curve.first()->y);
      else
          p = get_point_using_lineal_interpolation(airfoil_curve, next);

      p->scale(scale_value);

      p->rotate(AXIS_Y, rotate_value);

      Point3D *tp = get_translation_point(AXIS_Y, wingspan, dihedral_angle, arrow_angle);

      p->translate(*tp);
      delete tp;

      p->x *= -1;
      p->z *= -1;

      if(locate_point != NULL)
          p->translate(*locate_point);

      ref_curve.push_back(p);

      next += incr;
  }
}

/**
  * Generate the reference curves of the vertical tail
  */
void Aircraft::generate_vertical_tail_refcurves(int knpc)
{
//    QLOG_INFO() << "Aircraft::generate_vertical_tail_refcurves";

    int index = reference_curves_map[frc_vertical_tail];
    int index_taili = reference_curves_map[irc_tail_fuselage];
    int index_tailf = reference_curves_map[frc_tail_fuselage];

    Refcurve &ref_curve = reference_curves[index];
    Refcurve &ref_curve_taili = reference_curves[index_taili];
    Refcurve &ref_curve_tailf = reference_curves[index_tailf];

    ref_curve.resize(knpc);
    ref_curve[0] = ref_curve_taili[0];
    ref_curve[knpc - 1] = ref_curve_tailf[0];

    Point3D *u = *(ref_curve.first()) - *(ref_curve.last());

    assert(find_a_point != NULL);

    double increment = 1.0 / (knpc - 1);
    double lambda = increment;
    for(int col = 1; col < knpc - 1; col++)
    {
        ref_curve[col] = find_a_point(*ref_curve[0], *u, lambda);
        lambda += increment;
    }

    delete u;
}

/**
  * Generate the reference curves of the horizontal tail
  */
void Aircraft::generate_horizontal_tail_refcurves()
{
//    QLOG_INFO() << "Aircraft::generate_horizontal_tail_refcurves";
    QMap<QString, float> &htail_params = (*_parameters)[s_horizontal_tail];

    int knpc = htail_params[htail_npc] + 1;

    double x = htail_params[htail_xfa];
    double z = htail_params[htail_h];
    Point3D _locatep(-x, 0.0, -z);

    create_wcurve(reference_curves_map[irc_horizontal_tail], knpc, htail_root, 0.0,
                  htail_params[htail_cra], htail_params[htail_ara], 0.0, 0.0, &_locatep);
    create_wcurve(reference_curves_map[frc_horizontal_tail], knpc, htail_wingtip,
                  htail_params[htail_sib], htail_params[htail_cz], htail_params[htail_ara],
                  htail_params[htail_dib], htail_params[htail_lib], &_locatep);
}

/**
  * Draw a specify section of the geometry.
  * g_index - index of the vector of geometries where the section of a geometry is stored.
  * knpc - number of rows of the geometry's Stations
  * texture - if it is true, the geometry will be drawn with texture
  */
void Aircraft::draw_geometry(int g_index, int knpc, bool with_texture) const
{
//    QLOG_INFO() << "Uav_Joined_Wings::draw_geometry: " << g_index;
    QVector<Point3D *> knots = _geometries.at(g_index)->get_points(true);
    int col_s = knots.size() / knpc;

    glEnableClientState(GL_VERTEX_ARRAY);

    if(with_texture)
    {
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
        glPolygonMode(GL_BACK, GL_FILL);
        glPolygonMode(GL_FRONT, GL_FILL);
    }
    else
    {
        glPolygonMode(GL_BACK, GL_LINE);
        glPolygonMode(GL_FRONT, GL_LINE);
    }

    for(int row = 0; row < knpc - 1; row++)
    {
        QVector<Point3D> l_side;
        QVector<Point3D> r_side;
        QVector<Point> text_coord;

        for(int col = 0; col < col_s; col++)
        {
            Point3D *fst = knots.at((knpc * col) + row + 1);
            Point3D *snd = knots.at((knpc * col) + row);

            if(with_texture)
            {
                if(col > 0)
                    text_coord << Point(0.0, 0.0) << Point(0.0, 1.0)
                            << Point(1.0, 0.0) << Point(1.0, 1.0);
            }

            l_side << Point3D(fst->x, fst->y, fst->z) << Point3D(snd->x, snd->y, snd->z);
            r_side << Point3D(fst->x, -fst->y, fst->z) << Point3D(snd->x, -snd->y, snd->z);
        }

        if(with_texture)
        {
            glBindTexture(GL_TEXTURE_2D, get_texture_name("GREY"));
            glTexCoordPointer(2, GL_DOUBLE, 0, text_coord.constData());
        }
        else
        {
            QVector<int> color_values(3);
            get_color("BLACK", color_values);
            glColor3ub(color_values.at(0), color_values.at(1), color_values.at(2));
        }


        // left
        glVertexPointer(3, GL_DOUBLE, 0, l_side.constData());
        glDrawArrays(GL_QUAD_STRIP, 0, l_side.size());

        // right
        glVertexPointer(3, GL_DOUBLE, 0, r_side.constData());
        glDrawArrays(GL_QUAD_STRIP, 0, r_side.size());
    }

    glEnableClientState(GL_VERTEX_ARRAY);

    if(with_texture)
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}

/**
  * Draw a step of the simulation
  * step - the current step of the simulation to draw.
  * with_texture - if it is true the simulation will be drawn with texture
  */
void Aircraft::draw_simulation(int step, bool with_texture) const
{
//    QLOG_INFO() << "Draw Simulation";

    QVector<Zone> zones = (*(_zones.at(step - 1))).zones;
    QVector<QString> colours = (*(_zones.at(step - 1))).colours;
    QVector<int> columns = (*(_zones.at(step - 1))).columns;

    glEnableClientState(GL_VERTEX_ARRAY);
    if(not with_texture)
    {
        glPolygonMode(GL_BACK, GL_LINE);
        glPolygonMode(GL_FRONT, GL_LINE);
    }
    else
    {
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
        glPolygonMode(GL_BACK, GL_FILL);
        glPolygonMode(GL_FRONT, GL_FILL);
    }

    for(int n_zone = 0; n_zone < zones.size(); n_zone++)
    {
        QVector<Point3D *> c_zone = zones.at(n_zone);
        int col_s = columns.at(n_zone);
        int row_s = c_zone.size() / col_s;
        QString colour = colours.at(n_zone);

        for(int row = 0; row < row_s - 1; row++)
        {
            QVector<Point3D> l_side;
            QVector<Point> text_coord;

            for(int col = 0; col < col_s; col++)
            {
                Point3D fst = *c_zone.at((row_s * col) + row);
                Point3D snd = *c_zone.at((row_s * col) + row + 1);

                if(with_texture)
                {
                    if(col > 0)
                        text_coord << Point(0.0, 0.0) << Point(0.0, 1.0)
                                << Point(1.0, 0.0) << Point(1.0, 1.0);
                }

                l_side << fst << snd;
            }

            // left
            if(not with_texture)
            {
                QVector<int> color_values(3);
                get_color(colour, color_values);
                glColor3ub(color_values.at(0), color_values.at(1), color_values.at(2));
            }
            else
            {
                glBindTexture(GL_TEXTURE_2D, get_texture_name(colour));
                glTexCoordPointer(2, GL_DOUBLE, 0, text_coord.constData());
            }

            glVertexPointer(3, GL_DOUBLE, 0, l_side.constData());

            glDrawArrays(GL_QUAD_STRIP, 0, l_side.size());
        }
    }

    if(with_texture)
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    glDisableClientState(GL_VERTEX_ARRAY);
}

/**
  * Create the geometry of the fuselage
  * returns The geometry of the fuleage
  */
AGeometry *Aircraft::create_fuselage()
{
//    cout << "TODO: Uav_joined_wings.create_fuselage" << endl;
    AGeometry *_fuselage = new Geometry();

    QMap<QString, float> &fuselage_params = (*_parameters)[s_fuselage];
    QMap<QString, float> &wings_params = (*_parameters)[s_wings];

    int knpm = fuselage_params[fuselage_npm] + 1;
    int knpf = fuselage_params[fuselage_npf] + 1;
    int knpc = wings_params[wings_npc] + 1;

    AGeometry *_st1 = new Station(reference_curves[reference_curves_map[irc_snout_fuselage]],
                                  reference_curves[reference_curves_map[frc_snout_fuselage]],
                                  knpm);
    _fuselage->add_component(_st1);

    int nknots_ff = calculate_nknots(*reference_curves[reference_curves_map[irc_wing_fuselage]].at(0),
                                     *reference_curves[reference_curves_map[irc_wing_fuselage]].at(1),
                                     *reference_curves[reference_curves_map[frc_snout_fuselage]].at(0)) + 1;

    AGeometry *_st2 = new Station(reference_curves[reference_curves_map[frc_snout_fuselage]],
                                  reference_curves[reference_curves_map[irc_wing_fuselage]],
                                  nknots_ff);
    _fuselage->add_component(_st2);

    AGeometry *intersection = new Geometry();
    for(int i = 0; i < knpc - 1; i++)
    {
        QString rcurvei(rc_wing_fuselage);
        QString rcurvef(rc_wing_fuselage);
        rcurvei.append(QString::number(i));
        rcurvef.append(QString::number(i + 1));

        AGeometry *_aux = new Station(reference_curves[reference_curves_map[rcurvei]],
                                      reference_curves[reference_curves_map[rcurvef]], 2);

        intersection->add_component(_aux);
    }
    _fuselage->add_component(intersection);

    int nknots_bf = calculate_nknots(*reference_curves[reference_curves_map[irc_back_fuselage]].at(0),
                                     *reference_curves[reference_curves_map[irc_back_fuselage]].at(1),
                                     *reference_curves[reference_curves_map[irc_tail_fuselage]].at(0));
    AGeometry *_st3 = new Station(reference_curves[reference_curves_map[irc_back_fuselage]],
                                  reference_curves[reference_curves_map[frc_back_fuselage]],
                                  nknots_bf);
    _fuselage->add_component(_st3);

    AGeometry *_st4 = new Station(reference_curves[reference_curves_map[irc_tail_fuselage]],
                                  reference_curves[reference_curves_map[frc_tail_fuselage]],
                                  knpc);
    _fuselage->add_component(_st4);

    _fuselage->calculate_points();

    wf_start_intersection_panel = ((knpm - 1) * (knpf - 1)) + ((knpf - 1) * (nknots_ff - 1)) +
            ((knpf - 1) / 2);

    return _fuselage;
}

/**
  * Create the geometry of the wings
  * returns The geometry of the wings
  */
AGeometry *Aircraft::create_wings()
{
//    QLOG_INFO() << "Aircraft::create_wings";
    int nknots_ifw, nknots_efw;

    assert(calculate_nknots != NULL);

    nknots_ifw = calculate_nknots(*reference_curves[reference_curves_map[irc_wings]].at(0),
                                  *reference_curves[reference_curves_map[irc_wings]].at(1),
                                  *reference_curves[reference_curves_map[frc_wings]].at(0));
    nknots_efw = calculate_nknots(*reference_curves[reference_curves_map[irc_externw]].at(0),
                                  *reference_curves[reference_curves_map[irc_externw]].at(1),
                                  *reference_curves[reference_curves_map[frc_externw]].at(0));

    AGeometry *_st1 = new Station(reference_curves[reference_curves_map[irc_wings]],
                                  reference_curves[reference_curves_map[frc_wings]],
                                  nknots_ifw);
    AGeometry *_st2 = new Station(reference_curves[reference_curves_map[irc_externw]],
                                  reference_curves[reference_curves_map[frc_externw]],
                                  nknots_efw);

    AGeometry *_fwd_wing = new Geometry();

    _fwd_wing->add_component(_st1);
    _fwd_wing->add_component(_st2);

    _fwd_wing->calculate_points();

    return _fwd_wing;
}

/**
  * Create the geometry of the vertical tail
  * returns The geometry of the vertical tail
  */
AGeometry *Aircraft::create_vertical_tail()
{
//    QLOG_INFO() << "Aircraft::create_vertical_tail";

    int knpev = (*_parameters)[s_vertical_tail][vtail_npev] + 1;

    AGeometry *_st1 = new Station(reference_curves[reference_curves_map[irc_vertical_tail]],
                                  reference_curves[reference_curves_map[frc_vertical_tail]],
                                  knpev);

    AGeometry *_vtail= new Geometry();
    _vtail->add_component(_st1);

    _vtail->calculate_points();

    return _vtail;
}

/**
  * Create the geometry of the horizontal tail
  * returns The geometry of the horizontal tail
  */
AGeometry *Aircraft::create_horizontal_tail()
{
//    QLOG_INFO() << "Aircraft::create_horizontal_tail";
    int nknots_bw;

    nknots_bw = calculate_nknots(*reference_curves[reference_curves_map[irc_horizontal_tail]].at(0),
                                 *reference_curves[reference_curves_map[irc_horizontal_tail]].at(1),
                                 *reference_curves[reference_curves_map[frc_horizontal_tail]].at(0));

    AGeometry *_st1 = new Station(reference_curves[reference_curves_map[irc_horizontal_tail]],
                                  reference_curves[reference_curves_map[frc_horizontal_tail]],
                                  nknots_bw);

    AGeometry *_htail = new Geometry();

    _htail->add_component(_st1);

    _htail->calculate_points();

    return _htail;
}
